home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
text.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
60KB
|
2,470 lines
/*
* $Id: text.c,v 0.91 1994/02/20 00:53:02 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* Purpose:
* Place arbitrary text on the image with automatic font switching to get
* Greek letters, with same input method as in TeX.
*
* Needs a lot of more cleanup and abstraction. Also, this routine
* does its own SaveUnders. Without support like X Pixmap, it is hard
* to avoid framebuffer read.
*
* Moving text around is by default done via a simulated double buffereing
* mechanism, which unfortunately could be slow on R3k or slower machines.
*
* BUGS: there is a leak in fontcache to avoid a bug in the fontmanager
* (on IRIX 4.0.5 only ?), currently replying on font cache flushing to
* limit the leak.
*
*
*/
#if !defined(lint) && defined(F_ID)
char *id_text = "$Id: text.c,v 0.91 1994/02/20 00:53:02 zhao Pre-Release $";
#endif
#include "bit.h"
#include "fmclient.h"
#include "extern.h"
#include "dmalloc.h"
#ifndef NO_FM_BUG
#define FM_BUG
#endif
#include "symbol.h" /* fonts and special symbols */
#include "tsdef.h" /* Token defination */
/***************** Limits and defines ****************************/
#define MINFSIZE 3.0 /* min fontsize allowd */
#define MAXFSIZE 150.0 /* max fontsize allowd */
#define MAXTEXT 31 /* max strings per image */
#define MAXFONT 25 /* max no. of fonts */
#define MAXSTR 512 /* max string length */
#define SSHIFT 1 /* shadow shift */
#define SSTEP 15 /* every sstep increase shadow by 1 */
#define BW 1 /* for engrave & embossed */
/* if requested font in particular size is not availble, the font
manager substitutes another one, and thus the bounding box
maybe wrong. Add EXTRA to the bounding box to guarantee cleanup
*/
#define EXTRA 15 /* extra space for bounding box */
#define TC 0 /* text color index */
#define FC 1 /* frame color index */
#define BC 2 /* bk color index */
/*************** Local variables ******************************/
static fmfonthandle fh[MAXFONT];/* All 1pt sized fonts */
static char *fontname[MAXFONT]; /* and their names */
static int mfindex; /* math(symbol) font index */
static fmfonthandle mathfont[5];/* in different sizes */
static fmfonthandle textfont[5];/* text font in different sizes */
static int pmatch; /* if use printer width info */
static int immediate = 1; /* default rendering method */
static int placement = 1; /* alignment */
static Line cline; /* current line */
static IPTR limg; /* local copy of image pointer */
/** Special effects */
enum seffects
{
SE_normal, SE_shadow, SE_engraved, SE_embossed
};
static const char *seffect_name[] =
{
"Normal", "Shadow", "Engraved", "Embossed", 0
};
/* size command and corresponding font size delta */
static const char *size_cmd[] =
{
"normal", "tiny", "small", "large", "huge"
};
static float fdelta[] =
{
0, -4, -2, 2, 4
};
/***************************************************************
* Text structure. Positions are relative to the the rasterimage
**************************************************************/
typedef struct
{
char *str; /* input string */
Line *line; /* tokenized string */
int findex; /* index into fh */
fmfonthandle cfont; /* scaled, ready to use */
int xi, yi; /* starting position >0 */
int xt, yt; /* with proper justi */
int w, h; /* repaint region */
float size; /* text size int points */
float rot; /* rot angle 0 <rot <360 */
int col[3][4]; /* text, bk and frame color */
int colm[4]; /* scaled with factor < 1 */
int colp[4]; /* scaled with factor > 1 */
short height; /* font height */
short slant; /* slant in x dir */
short descent; /* slant in y dir */
short frame; /* if put a frame on */
short bk; /* if frame and bk */
short place; /* 0 l, 1 c, 2 r */
short se; /* if shadow */
}
Text_t;
static Text_t textbuf[MAXTEXT]; /* text saved */
static Text_t cttext; /* working buf */
static Text_t *tptr = &cttext; /* current text line */
static char strbuf[MAXSTR + 2]; /* plus cursor + '\0' */
static int xi, yi, xf, yf; /* rectangular bounds */
static float vec[4][2]; /* rotated coordinats */
static int lxi, lyi, lxf, lyf; /* For saveunder */
/******************* Local functions ***************************/
static Line *getlinemem(void);
static void dupline(Line *, const Line *);
static void freeline(Line *);
static void sim_dbl_text_move(Text_t *);
static void sgl_text_move(Text_t *);
static void dbl_text_move(Text_t *);
static void text_rasterize(Text_t *);
static void
save_last_position(void)
{
lxi = xi - EXTRA;
lyi = yi - EXTRA;
lxf = xf + EXTRA;
lyf = yf + EXTRA;
}
/****************************************************************
* Find next availale slot
****************************************************************/
static Text_t *
text_next(void)
{
register Text_t *tx = textbuf + MAXTEXT;
while (--tx >= textbuf && tx->line)
;
if (tx < textbuf)
{
M_err("NextText", "out of bounds");
return 0;
}
return tx;
}
/*****************************************************************
* save current text (tptr) into the structure
*****************************************************************/
static int
text_save(void)
{
Text_t *tx = text_next();
if (tx) /* ok */
{
memcpy(tx, tptr, sizeof(*tx));
tx->str = strdup(strbuf);
tx->line = getlinemem();
dupline(tx->line, &cline);
/* convert to image distance based */
tx->xi -= limg->xi;
tx->yi -= limg->yi;
}
return tx ? 0 : -1;
}
/****************************************************************
* Remove a saved text
*****************************************************************/
static void
text_free(Text_t * t)
{
if (t)
{
if (t->str)
free(t->str);
freeline(t->line);
t->line = 0;
}
}
/********************************************************************
* Total number of text saved so far. Also re-arranges text
* in a consecutive manner
*******************************************************************/
static Text_t *ttt[MAXTEXT];
int
number_of_text(void)
{
register int i = 0;
register Text_t *tx = textbuf + MAXTEXT;
while (--tx >= textbuf)
if (tx->line)
ttt[i++] = tx;
return i;
}
/******************************************************************
* get line width, taking into account of font change and size change
*******************************************************************/
static int
get_line_width(Line * line)
{
int i;
Token *t = line->token;
int tw = 0;
for (i = line->ntokens; --i >= 0; t++)
{
tw += fmgetstrwidth(t->math ?
mathfont[t->isize] : textfont[t->isize], t->str);
}
return tw;
}
/*****************************************************************
* Check if current font is the same as the last: Free all fonts
* used if different and setnewfonts will re-generate needed fonts.
****************************************************************/
static int
font_diff(Text_t * t)
{
int diff;
static int cfindex = -1; /* cache for last font */
static float csize = -1.0; /* cache for last font */
static lpmatch = -1;
diff = ((cfindex != t->findex) || /* diff font */
(lpmatch != pmatch) || /* diff font */
(Abs(csize - t->size) > 0.1)); /* diff size */
/*
* free the old font if different. Can't do this because IRIX 4.05? has a
* bug that will produce a segmentation fault
*/
if (diff)
{ /* not first time */
#ifndef FM_BUG /* The workaround */
if (cfindex >= 0)
{
int i;
for (i = 0; i < 5; i++)
{
fmfreefont(mathfont[i]);
fmfreefont(textfont[i]);
}
}
#endif
cfindex = t->findex;
lpmatch = pmatch;
csize = t->size;
}
return diff;
}
/***********************************************************
* Set text and math font for possible different sizes
***********************************************************/
static void
set_new_font(Text_t * t)
{
static fmfontinfo info;
long owin = winget();
static fmfonthandle lcfont; /* scaled, ready to use */
float tmpfsize[6], tt;
int i;
float *tf = tmpfsize, *td = fdelta;
/* set new font only if different from last */
if (font_diff(t))
{
/* get all the sizes */
*tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
*tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
*tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
*tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
*tf = (tt = t->size + *td) > 1.0 ? tt : MINFSIZE;
/* validate all used fonts */
for (i = 0; i < 5; i++)
{
mathfont[i] = fmscalefont(fh[mfindex], tmpfsize[i]);
textfont[i] = fmscalefont(fh[t->findex], tmpfsize[i]);
}
/* current font */
t->cfont = lcfont = textfont[0];
M_info("SetNewFont", "FontCacheused: %ld", fmgetcacheused());
/* install font */
set_current_window(win_id);
fmsetfont(t->cfont);
fmgetfontinfo(t->cfont, &info);
}
/* record basic properties */
t->cfont = lcfont;
t->descent = info.yorig;
t->slant = info.xorig;
t->height = info.height - t->descent + 1;
if (owin > 0)
set_current_window(owin);
}
/********************************************************************
* Find the box that encloses the text for repaint. VEC[4][i] are
* the rotated coordinates of the box that bounds the text
* while (xi, yi), (xf, yf) are the coordinates of the bounding box
* that bounds everything.
*
* the unrotated bounding box:
*
* (-slant , h) (w + shift, h)
* (-slant, descent) (w+shift, descent)
*******************************************************************/
static double pagematrix[3][2];
#include <math.h>
#define PI 3.1415926
static void
get_bounding_box(Text_t * t)
{
float sina, cosa;
int i, sshift;
float xo, yo;
int ww, hh; /* the true width of text */
float cxo, sxo, cyo, syo;
float cww, sww, chh, shh;
float xsf, ysf;
/* basic size */
t->w = get_line_width(t->line) + t->size / 5;
t->h = t->height;
/* calculate the shift caused by special effects */
if (t->se == SE_shadow)
{
sshift = (SSHIFT + (t->size / SSTEP));
xo = -(t->slant + 1);
yo = -(t->descent + 1) - sshift - 1;
ww = t->w + sshift;
hh = t->h;
}
else if (t->se == SE_normal)
{
sshift = 0;
xo = -(t->slant + 1);
yo = -(t->descent + 1) - sshift - 2;
ww = t->w;
hh = t->h;
}
else
{
sshift = 1.0;
xo = -(t->slant + 1) - 1;
yo = -(t->descent + 1) - sshift - 2;
ww = t->w + 2;
hh = t->h + 2;
}
cosa = cos(t->rot * (PI / 180.0));
sina = sin(t->rot * (PI / 180.0));
cww = cosa * ww;
sww = sina * ww;
t->xt = t->xi;
t->yt = t->yi;
if (t->place == TCENTER)
{ /* center */
xsf = 0.5 * cww;
ysf = 0.5 * sww;
}
else if (t->place == TRIGHT)
{ /* left adjusted */
xsf = cww;
ysf = sww;
}
else
{
xsf = 0.0;
ysf = 0.0;
}
t->xt -= xsf;
t->yt -= ysf;
/* get the rotated coordinates for the 4pt */
/* (xo, yo) */
vec[0][0] = (cxo = cosa * xo) - (syo = sina * yo) + t->xt;
vec[0][1] = (sxo = sina * xo) + (cyo = cosa * yo) + t->yt;
/* (w + shift, yo) */
vec[1][0] = cww - syo + t->xt;
vec[1][1] = sww + cyo + t->yt;
/* (ww, h) */
vec[2][0] = cww - (shh = sina * hh) + t->xt;
vec[2][1] = sww + (chh = cosa * hh) + t->yt;
/* (xo, h) */
vec[3][0] = cxo - shh + t->xt;
vec[3][1] = sxo + chh + t->yt;
/* get lower-left and upper-right */
xi = xf = vec[0][0];
yi = yf = vec[0][1];
for (i = 1; i < 4; i++)
{
if (xi > vec[i][0])
xi = vec[i][0];
if (xf < vec[i][0])
xf = vec[i][0];
if (yi > vec[i][1])
yi = vec[i][1];
if (yf < vec[i][1])
yf = vec[i][1];
}
/* enlarge by 1 on all sides */
xi--;
yi--;
xf++;
yf++;
}
/********************************************************************
* Generate a framebox
*******************************************************************/
static void
make_frame(Text_t * t)
{
int i;
if (t->bk)
{
Color4(t->col[BC]);
bgnpolygon();
for (i = 0; i < 4; i++)
v2f(vec[i]);
endpolygon();
}
if (t->frame)
{
Color4(t->col[FC]);
bgnclosedline();
for (i = 0; i < 4; i++)
v2f(vec[i]);
endclosedline();
}
}
/**********************************************************************
* We have the option to clean up the text by saving the screen or repaint
* with the raster matrix depending on the definition of READSCR
*
* Do not know about Indigo, supposedly repeated read and write degrade the
* image and in that case READSCR should be undefined.
**********************************************************************/
#define READSCR
static void **spp;
/****************************************************************
* do a SaveUnder. If READSCR is not defined, we can use the image
* in core as the backing store, save_under does nothing
***************************************************************/
static void
save_under(void)
{
#ifdef READSCR
static int lsxi, lsyi, lsxf, lsyf;
int moved;
moved = (lxi - lsxi) || (lyi - lsyi) || (lxf - lsxf) || (lyf - lsyf);
if (moved || !spp)
{
lsxi = lxi;
lsyi = lyi;
lsxf = lxf;
lsyf = lyf;
free_mat(spp);
spp = get_mat(lyf - lyi + 1, lxf - lxi + 1, imgptr->esize);
set_current_window(win_id);
Rectread(lxi, lyi, lxf, lyf, spp[0]);
}
#endif
}
static void
restore_piece(int txi, int tyi, int txf, int tyf)
{
if (txi != txf && spp)
{
set_current_window(win_id);
reshapeviewport();
#ifdef READSCR
PI_rectwrite(txi, tyi, txf, tyf, spp[0]);
#else
img_rect_redraw(limg, txi, tyi, txf - txi + 1, tyf - tyi + 1);
#endif
}
}
/****************************************************************
* The actuall routine that does the rendering at given location.
* It does not rememeber where it did it.
****************************************************************/
static void
render_line(int x, int y, Line * line)
{
Token *t = line->token, *ts;
static int lastmath = -1;
static float lastsize = -1.0;
set_current_window(win_id);
reshapeviewport();
cmov2i(x, y);
for (ts = t + line->ntokens; t < ts; t++)
{
if (lastmath != t->math || Abs(lastsize - t->size) > 0.1)
{
fmsetfont(t->math ? mathfont[t->isize] : textfont[t->isize]);
}
fmprstr(t->str);
}
}
/**********************************************************************
* Routine takes care of frame and rotation and call render_line to
* do the actual rendering
*********************************************************************/
static void
text_draw_only(Text_t * t)
{
int sshift = (SSHIFT + (t->size / SSTEP)) * (t->se != SE_normal);
set_current_window(win_id);
reshapeviewport();
if (t->bk || t->frame)
make_frame(t);
if (t->rot >= 0.1)
{
fmgetpagematrix(pagematrix);
fmrotatepagematrix(t->rot);
}
if (t->se == SE_shadow)
{
scale_color(t->col[TC], 0.3, t->colm, 0, PCMAXV);
Color4(t->colm);
render_line(t->xt + sshift, t->yt - sshift, t->line);
}
else if (t->se == SE_engraved)
{
scale_color(t->col[TC], 0.3, t->colm, 80, PCMAXV);
scale_color(t->col[TC], 2.0, t->colp, 200, PCMAXV);
Color4(t->colm);
render_line(t->xt - BW, t->yt + BW, t->line);
Color4(t->colp);
render_line(t->xt + BW, t->yt - BW, t->line);
}
else if (t->se == SE_embossed)
{
scale_color(t->col[TC], 0.3, t->colm, 80, PCMAXV);
scale_color(t->col[TC], 2.0, t->colp, 200, PCMAXV);
Color4(t->colp);
render_line(t->xt - BW, t->yt + BW, t->line);
Color4(t->colm);
render_line(t->xt + BW, t->yt - BW, t->line);
}
/* the real text */
Color4(t->col[TC]);
render_line(t->xt, t->yt, t->line);
/* Restore the pagematrix and free fontcache used */
if (t->rot >= 0.1)
{
fmsetpagematrix(pagematrix);
}
}
/********************************************************************
* Draw and show
********************************************************************/
static void
text_draw(Text_t * t)
{
text_draw_only(t);
#ifndef SGL_BUF
if (double_buf)
{
swapbuffers();
}
#endif
}
/*****************************************************************
* This routine takes care of rendering and moving, i.e., remember
* where we did it.
*****************************************************************/
static void
sgl_text_move(Text_t * t)
{
/* repaint the region where old text was */
restore_piece(lxi, lyi, lxf, lyf);
/* need to do this everytime to get the correct box */
get_bounding_box(t);
/* remember where we will do it */
save_last_position();
save_under();
text_draw_only(t);
}
/*****************************************************************
* move text in double buffer mode
*****************************************************************/
static int lastwme;
static void
dbl_text_move(Text_t * t)
{
/* need to do this everytime to get the correct box */
get_bounding_box(t);
/*
* all text has the back buffer completely clean except when window
* manager does the redraw, need to clean up the back buffer when last
* redraw is wme
*/
if (lastwme)
{
restore_piece(lxi, lyi, lxf, lyf);
lastwme = 0;
}
/* remember where we will do it */
text_draw(t);
restore_piece(lxi, lyi, lxf, lyf);
save_last_position();
save_under();
}
static void
text_move(Text_t * t)
{
long owin = winget();
set_current_window(win_id);
reshapeviewport();
/*
* can't use sim_dbl_buffer here because the need to completely redraw
* the text string
*/
(double_buf ? dbl_text_move : sgl_text_move) (t);
if (owin > 0)
set_current_window(owin);
}
/********************************************************************
* This is the routine that sets new font (font family, size, rotation)
*********************************************************************/
static void
render_text(Text_t * t)
{
if (!t || !t->line)
return;
set_new_font(t);
text_move(t);
}
/*********************************************************************
* initialize all fonts and get the font handle. Remove unavailable font
* names
********************************************************************/
static int
init_fonts(void)
{
int i;
static int n = -1;
if (n > 0)
return n;
if (totalfont > MAXFONT)
{
totalfont = MAXFONT - 1;
}
fminit();
/*
* there are leaks currently, we need to make sure cache is large enuf,
* about 2M
*/
#ifdef FM_BUG
fmsetcachelimit((1500 * 1000) / FMCACHE_QUANTUM);
#endif
fmcacheenable();
n = i = 0;
while (i < totalfont)
{
if ((fh[n] = fmfindfont(fonts[i])))
{
fontname[n] = fonts[i];
if (strcmp(fontname[n], "Symbol") == 0)
mfindex = n;
n++;
}
i++;
}
fontname[n] = 0;
return totalfont = n;
}
/*******************************************************************
* Given a fontname fn, try to get the font index, findfont return.
* If fn is bad, first available font index is returned.
* MUST not return bogus index. On a related note, it is best
* to have the first font index entry be a mon-spaced font.
*******************************************************************/
static int
get_font_index(const char *fn)
{
int found, i;
if (!init_fonts())
{
Bark("InitText", "Unable to load any fonts!!");
return 0;
}
if (!fn || !*fn)
return 0;
i = -1;
do
{
i++;
found = strcmp(fontname[i], fn) == 0;
}
while (!found && i < totalfont - 1);
return found ? i : 0;
}
/*******************************************************************
* Support routines that parse the input string into tokens with many
* attributes
*****************************************************************{*/
/* allocate memory for struct Line */
static Line *
getlinemem(void)
{
/* assuming char * has all zero bits for null */
return calloc(1, sizeof(Line));
}
/* make a copy of struct line */
static void
dupline(Line * to, const Line * from)
{
const Token *t = from->token, *ts;
Token *pt = to->token;
if (!memcpy(to, from, sizeof(*from)))
return;
/* we are not done yet, members of line malloced */
for (ts = t + from->ntokens; t < ts; t++, pt++)
if (t->str)
pt->str = strdup(t->str);
return;
}
/* Free all memory allocated for a line */
static void
freeline(Line * line)
{
Token *t, *ts;
if (!line)
return;
for (t = line->token, ts = t + line->ntokens; t < ts; t++)
{
if (t->str)
free(t->str);
t->str = 0;
}
}
#ifdef SC_DEBUG
static void
print_tokens(Line * line)
{
int c;
fprintf(stderr, "Total %d tokens\n", line->ntokens);
for (c = 0; c < line->ntokens; c++)
fprintf(stderr, "math=%d size=%.1f is=%d str=%s^\n",
line->token[c].math, line->token[c].size,
line->token[c].isize, line->token[c].str);
}
#endif
/*************************************************************
* check if a particular token is a sizing command, i.e.,
* \small, \large etc
**************************************************************/
static int
is_size(const char *p)
{
int i;
for (i = sizeof(size_cmd) / sizeof(char *); --i >= 0;)
if ((size_cmd[i][0] == *p) && strcmp(size_cmd[i], p) == 0)
return i;
return -1;
}
/******************************************************************
* Add a new token to line and fix the special symbols on the fly
* sz is the base size while isize is index into the modifier
*******************************************************************/
#include <ctype.h>
static void
new_token(Line * line, int m, float sz, int isize, char *str)
{
register char *s = str;
char token[MAXSTR], ltok[MAXSTR];
char *ct, *lct;
Token *t = &line->token[line->ntokens];
if (!*str)
return;
t->math = m;
if (isize < 0)
isize = 0;
t->isize = isize;
t->size = sz + fdelta[isize];
/* there is no point print a string you can't see */
if (t->size < MINFSIZE)
t->size = MINFSIZE;
if (t->str)
free(t->str);
ct = token;
while (*s)
{
switch (*s)
{
case '\\':
lct = ltok;
while (*++s && isalnum(*s))
*lct++ = *s;
*lct = '\0';
*ct = '\0';
/* mathcode returns a string of length 1 or more */
strcat(token, m ? mathcode(ltok) : spcode(ltok));
ct = token + strlen(token);
--s;
break;
default:
*ct++ = *s;
break;
}
if (*s)
s++;
}
*ct = '\0';
t->str = strdup(token);
line->ntokens++;
if (line->ntokens >= MAXTOK)
{
M_warn("TextAddToken", "No. of tokens out of bounds");
line->ntokens = MAXTOK - 1;
}
}
/**********************************************************************
* Break a line into tokens. A token is defined as a string uninterrupted
* by font switching ($) or size change \small etc
* Base size is sz
**********************************************************************/
static void
tokenize(char *str, Line * line, float sz)
{
register char *p = str;
register char *ct, *lct;
register int math = 0;
float size = sz;
int isize = 0;
register int c;
char ctoken[MAXSTR], ltoken[MAXSTR];
line->ntokens = 0;
ct = ctoken;
ltoken[0] = '\0';
while (p && *p)
{
switch (*p)
{
case '$':
*ct = '\0';
new_token(line, math, size, isize, ctoken);
ct = ctoken;
math = !math;
break;
case '\\':
c = *++p; /* skip \\ */
if (c == '\\' || c == '$')
{ /* escape */
*ct++ = c;
}
else if (c)
{ /* a true token. */
lct = ltoken;
*lct++ = '\\';
*lct++ = c;
while (*++p && isalpha(*p))
*lct++ = *p;
*lct = '\0';
/* check if sizing command */
if ((c = is_size(ltoken + 1)) >= 0)
{
*ct = '\0';
new_token(line, math, size, isize, ctoken);
isize = c;
ct = ctoken;
}
else
{ /* not a size command, keep it */
*lct = '\0';
*ct = '\0';
strcat(ctoken, ltoken);
ct = ctoken + strlen(ctoken);
}
--p; /* backup */
}
break;
default:
*ct++ = *p;
}
if (*p)
p++;
}
*ct = '\0';
if (math)
M_info("ScanLine", "Unfinished math");
if (math)
{
/* show only complete symbols */
p = (ct = strrchr(ctoken, ' ')) ? ct : strrchr(ctoken, '\\');
if (p)
*p = '\0';
}
new_token(line, math, size, isize, ctoken);
#ifdef SC_DEBUG
print_tokens(line);
#endif
}
/***********************************************************************
* END OF SUPPORT ROUTINES
*******************************************************************}*/
/*
* routine to add text. To be called non-interactively.
*/
void
img_add_text(IPTR im, const char *s, const char *f,
float tsize, float trot, rgba_t tc, int x, int y, int bk,
rgba_t bc, int fr, rgba_t fc, int sh, int pl)
{
Text_t *t;
int i, r, g, b;
if (!im || !s)
return;
t = text_next();
memset(t, 0, sizeof(*t));
t->line = getlinemem();
t->str = strdup(s);
t->place = 0;
t->xi = x;
t->yi = y;
Unpack(tc, r, g, b);
t->col[TC][0] = r;
t->col[TC][1] = g;
t->col[TC][2] = b;
Unpack(fc, r, g, b);
t->col[FC][0] = r;
t->col[FC][1] = g;
t->col[FC][2] = b;
Unpack(bc, r, g, b);
t->col[BC][0] = r;
t->col[BC][1] = g;
t->col[BC][2] = b;
if (IS_CI(im))
{
for (i = 0; i < 3; i++)
t->col[i][3] = cmap_closematch(im->cmap, t->col[i][0],
t->col[i][1], t->col[i][2]);
}
t->bk = bk;
t->frame = fr;
t->size = tsize;
t->rot = trot;
t->findex = get_font_index(f);
t->se = sh;
t->place = pl;
tokenize(t->str, t->line, t->size);
}
const char *
get_text_fontname(int nt)
{
return fontname[ttt[nt]->findex];
}
float
get_text_fontsize(int nt)
{
return ttt[nt]->size;
}
const char *
get_text_string(int nt)
{
return ttt[nt]->str;
}
Line *
get_text_line(int nt)
{
return ttt[nt]->line;
}
int
get_text_placement(int nt)
{
return ttt[nt]->place;
}
void
get_text_location(int nt, int *x, int *y)
{
*x = ttt[nt]->xi;
*y = ttt[nt]->yi;
}
float
get_text_rotation(int nt)
{
return ttt[nt]->rot;
}
int
get_fm_cache(void)
{
return (fmcachelimit() * FMCACHE_QUANTUM / 1000);
}
int
get_fm_cacheused(void)
{
return (fmgetcacheused() / 1000);
}
/*************************************************************************
* get max sizes of texts that sticks out of the image, only approximately
* by using mono space and ignoring rotation
************************************************************************/
void
get_text_bounds(IPTR im, int *top, int *left, int *bottom, int *right)
{
Text_t *tx = textbuf + MAXTEXT;
int l = 0, b = 0, t = im->h, r = im->w;
while (--tx >= textbuf)
{
; /* to be written */
}
*top = t - im->h;
*left = -l;
*bottom = -b;
*right = r - im->w;
}
/*
* can't use limg because this routine can be called anywhere
*/
void
get_text_color(int nt, int *r, int *g, int *b)
{
int i;
if (IS_CI(imgptr))
{
i = ttt[nt]->col[TC][3];
*r = imgptr->cmap->ct[0][i];
*g = imgptr->cmap->ct[0][i];
*b = imgptr->cmap->ct[0][i];
}
else
{
*r = ttt[nt]->col[TC][0];
*g = ttt[nt]->col[TC][1];
*b = ttt[nt]->col[TC][2];
}
}
/*
* Delete all text saved and free all spaces
*/
void
del_text(void)
{
Text_t *tx = textbuf + MAXTEXT;
while (--tx >= textbuf)
{
if (!tx->line)
continue;
text_free(tx);
}
}
/******************************************************************
* Display current saved text.
*
* This routine could be called by various routines, including
* display, or window resizing events handlers. In any case,
* this routine should not alter buffer settings (back, front etc).
******************************************************************/
static int active; /* true if entered thru do_text */
void
display_text(IPTR im)
{
Text_t *t = textbuf + MAXTEXT;
init_text();
/* If bad image, silently return */
if (im->ok <= 0)
return;
while (--t >= textbuf)
{
if (t->line)
{
t->xi += im->xi;
t->yi += im->yi;
set_new_font(t);
get_bounding_box(t);
text_draw_only(t);
t->xi -= im->xi;
t->yi -= im->yi;
}
}
/*
* active means we are currently in text mode, and therefore need to
* re-draw the current text as well
*/
if (active)
{
set_new_font(tptr);
sgl_text_move(tptr);
lastwme = 1;
}
}
/***********************************************************************
* Save to and restore from disk. Could've dumped the whole structure out,
* but ASCII will be portable.
*/
void
dump_text(FILE * fp)
{
Text_t *t = textbuf + MAXTEXT;
fprintf(fp, "#TX %d\n", number_of_text());
/* can't stick # in front */
fputs(" Font Size Rot Text_t Tc Bc Fc X Y bk fr sh just\n", fp);
while (--t >= textbuf)
{
if (!t->line)
continue;
fprintf(fp, "#%s %.2f %.1f\n", fonts[t->findex], t->size, t->rot);
fprintf(fp, "%s\n", t->str);
fprintf(fp, "%g %g %g %g %g %g %g %g %g\n",
C2NC(t->col[0][0]), C2NC(t->col[0][1]), C2NC(t->col[0][2]),
C2NC(t->col[1][0]), C2NC(t->col[1][1]), C2NC(t->col[1][2]),
C2NC(t->col[2][0]), C2NC(t->col[2][1]), C2NC(t->col[2][2]));
fprintf(fp, "%d %d %d %d %d %d \n", t->xi, t->yi, t->bk, t->frame,
t->se, t->place);
}
}
/**********************************************************
* load text from disk.
***********************************************************/
void
load_text(IPTR im)
{
int n, i, j;
char fname[60], *p;
float fsize, trot, f;
int x, y, r, g, b;
rgba_t cc[3];
int bk, fr, sh, pl;
FILE *fp = im->fp;
while ((n = getc(fp)) != EOF && n != '#')
;
if (n != '#' || (n = getc(fp) != 'T') || (n = getc(fp)) != 'X')
return;
n = readpint(fp);
if (n <= 0)
return;
if (n >= MAXTEXT)
{ /* can't happen */
Bark("LoadText", "Total %d strings %s", n, outbound);
return;
}
M_info("LoadText", "%d strings found", n);
for (i = 0; i < n; i++)
{
while (fgets(strbuf, MAXSTR, fp) && strbuf[0] != '#')
;
if (strbuf[0] != '#')
{
M_warn("LoadText", "More are expected");
return;
}
sscanf(strbuf + 1, "%s %f %f", fname, &fsize, &trot);
fgets(strbuf, MAXSTR, fp);
/* remove newline */
if ((p = strchr(strbuf, '\n')))
*p = '\0';
for (j = 0; j < 3; j++)
{
f = readfloat(fp);
r = NC2C(f);
f = readfloat(fp);
g = NC2C(f);
f = readfloat(fp);
b = NC2C(f);
cc[j] = Pack(r, g, b);
}
x = readint(fp);
y = readint(fp);
bk = readint(fp);
fr = readint(fp);
sh = readint(fp);
pl = readint(fp);
img_add_text(im, strbuf, fname, fsize, trot, cc[TC],
x, y, bk, cc[BC], fr, cc[FC], sh, pl);
}
}
/********************************************************************
* convert text to gray. need only change the RGB representation.
* This routine is called after a type conversion
********************************************************************/
void
text_to_gray(void)
{
register int q;
Text_t *t = textbuf + MAXTEXT;
int *cc;
while (--t >= textbuf)
{
if (!t->line)
continue;
cc = t->col[TC];
q = rgb2gray(cc[0], cc[1], cc[2]);
cc[0] = cc[1] = cc[2] = q;
cc = t->col[BC];
q = rgb2gray(cc[0], cc[1], cc[2]);
cc[0] = cc[1] = cc[2] = q;
cc = t->col[FC];
q = rgb2gray(cc[0], cc[1], cc[2]);
cc[0] = cc[1] = cc[2] = q;
}
}
/*************************************************************
* Convert text color from RGB based to index based. Called
* after image type conversion, i.e., quantization. Not
* possible to honour exact colors, do the best we can
* from the colormap.
*************************************************************/
void
text_to_cmap(void)
{
Text_t *t = textbuf + MAXTEXT;
int *cc;
if (!IS_CI(imgptr))
return;
while (--t >= textbuf)
{
if (!t->line)
continue;
cc = t->col[TC];
cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
cc = t->col[BC];
cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
cc = t->col[FC];
cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
}
}
/************************************************************
*
* GUI part of the Text routines.
*
* Fills the Text_t structure and show its effect
*
************************************************************/
#define MINTXSIZE 1.0 /* minimum text size */
#define TXSTEP1 1.0 /* minimum delta */
#define TXSTEP2 5.0 /* maximum delta */
/*ARGSUSED */
static void
immediate_cb(FL_OBJECT * ob, long q)
{
immediate = fl_get_choice(ob) - 1;
}
/* default size for shortcuts */
static const float fsize[] =
{
5.0, 8.0, 10.0, 12.0, 14.0, 20.0
};
/* default shortcuts for orientation */
static const float rangle[] =
{
0, 90, 180, 270
};
static int indexs = 2; /* default size index */
static int indexr; /* default orientation */
static FL_FORM *textform;
static FL_OBJECT *fchoice;
static FL_OBJECT *input, *rcounter, *scounter, *effects;
static FL_OBJECT *col[3], *frame, *bk, *size[6], *ra[4];
/*********************************************************
* Initialize fonts, form entries, etc
*********************************************************/
static void create_form_text(void);
int
init_text(void)
{
int i;
char **p;
char tmp[20];
static int init;
static const char *dirtext[] =
{
"Horiz", "90", "180", "-90"
};
if (init > 0)
return init;
show_busy("LoadingFonts ...");
/* find all fonts */
if (!init_fonts())
{
Bark("InitText", "Unable to load any fonts!!");
return -1;
}
init = totalfont;
create_form_text();
/* fill the font choices */
fl_clear_choice(fchoice);
for (p = fontname; p && *p; p++)
fl_addto_choice(fchoice, *p);
fl_set_choice(fchoice, 1);
/* cleanr all size buttons and set default */
for (i = 0; i < 6; i++)
{
fl_set_button(size[i], 0);
sprintf(tmp, "%.0fpt", fsize[i]);
fl_set_object_label(size[i], tmp);
}
fl_set_button(size[indexs], 1);
/* set size counter default for arbitrary size */
fl_set_counter_precision(scounter, 1);
fl_set_counter_bounds(scounter, MINTXSIZE, MAXFSIZE);
fl_set_counter_step(scounter, TXSTEP1, TXSTEP2);
fl_set_counter_value(scounter, fsize[indexs]);
/* cleanr all rotation buttons and set default */
for (i = 0; i < 4; i++)
{
fl_set_button(ra[i], 0);
fl_set_object_label(ra[i], dirtext[i]);
}
fl_set_button(ra[indexr], 1);
/* set rotation counter default */
fl_set_counter_precision(rcounter, 0);
fl_set_counter_bounds(rcounter, 0.0, 360.0);
fl_set_counter_step(rcounter, 1, 10);
fl_set_counter_value(rcounter, rangle[indexr]);
/* misc */
fl_set_button(frame, 0);
fl_set_button(bk, 0);
fl_set_input_return(input, 1);
end_busy();
return init;
}
/*********************************************************************
* default Text color, Frame color and background color
********************************************************************/
static int lcol[][4] =
{
{0, 0, 0, 0}, /* text color */
{PCMAXV, 0, 0, 1}, /* frame color */
{PCMAXV, PCMAXV, PCMAXV, 0} /* background color */
};
/*****************************************************************
* Every time do_text is called, this routine will be called to set
* current size, color etc.
*****************************************************************/
static void
set_text_default(Text_t * t)
{
int i;
strcpy(strbuf, limg->ifile);
fl_set_input(input, strbuf);
t->size = fl_get_counter_value(scounter);
t->findex = fl_get_choice(fchoice) - 1;
t->frame = fl_get_button(frame);
t->se = fl_get_choice(effects) - 1;
t->bk = fl_get_button(bk);
t->rot = fl_get_counter_value(rcounter);
t->place = placement;
t->xi = win_w / 2 - 10;
t->yi = win_h / 2 - 10;
for (i = 0; i < 4; i++)
{
t->col[TC][i] = lcol[0][i];
t->col[FC][i] = lcol[1][i];
t->col[BC][i] = lcol[2][i];
}
tokenize(strbuf, t->line, t->size);
}
/***********************************************************
* Handle mouse events: Depending on various options,
* either double buffer, simulated double buffer and single
* buffer mode will be used. Note that in defered mode, current
* code is not capable of simulating double buffering without
* messing up the screen
**********************************************************/
static void
handle_mouse(Text_t * t)
{
void (*moveit) (Text_t *);
int mx, my;
if (!double_buf && simu_dbl_buffer && immediate)
text_rasterize(t);
/* hardware double buffering overrites other settings */
moveit = double_buf ? dbl_text_move :
((simu_dbl_buffer && immediate) ? sim_dbl_text_move : sgl_text_move);
M_info("TextMouse", moveit == dbl_text_move ? "DoubleBuffer" :
(moveit == sim_dbl_text_move ?
"SimuDblBuffer" : "SglBuffer"));
do
{
WHERE_R2W(mx, my, win_xo, win_yo);
if (mx != t->xi || my != t->yi)
{
show_mouse_position(mx, my);
t->xi = mx;
t->yi = my;
moveit(t);
}
}
while (mouse_down);
if (!double_buf && simu_dbl_buffer && immediate)
{
free_mat(spp);
spp = no_fail_get_subimage(imgptr, lxi, lyi,
lxf - lxi + 1, lyf - lyi + 1);
}
}
/*****************************************************************
* Simulate double buffering
*****************************************************************/
static int diffcolor;
#ifndef NO_NP_DBL /* { */
static void **rastext;
static int rash, rasw;
static int
attribute_diff(Text_t * t)
{
static float rotated = -1;
static int lframe = -1, lbk = -1;
static char lstrbuf[MAXSTR + 2]; /* plus cursor + '\0' */
static int leffects = -1;
int diff;
diff = (t->bk - lbk) || /* diff background */
(t->frame - lframe) || /* diff frame */
(Abs(t->rot - rotated) > 0.5) || diffcolor ||
(t->se - leffects) || strcmp(lstrbuf, strbuf);
if (diff)
{
lbk = t->bk;
lframe = t->frame;
rotated = t->rot;
leffects = t->se;
diffcolor = 0;
strcpy(lstrbuf, strbuf);
}
return diff;
}
static int
bad_magic_pix(rgba_t m)
{
if (IS_CPACK(imgptr))
{
rgba_t txc, bkc, fmc;
txc = Pack(lcol[TC][0], lcol[TC][1], lcol[TC][2]);
bkc = Pack(lcol[BC][0], lcol[BC][1], lcol[BC][2]);
fmc = Pack(lcol[FC][0], lcol[FC][1], lcol[FC][2]);
return (m == txc || m == bkc || m == fmc);
}
else
{
return (m == lcol[TC][3] ||
m == lcol[BC][3] ||
m == lcol[FC][3]);
}
}
/**********************************************************************
* Rasterize a text string: reads the screen buffer. Someday,
* it should be replaced with feekback from the GE.
* only should be called within handle_mouse
**********************************************************************/
static void
text_rasterize(Text_t * t)
{
static int incomplete;
static int cfindex = -1;
static int csize = -1.0;
static int lpmatch = -1;
rgba_t magicpix = 0;
/* can't simple use font_diff because render_text sets it */
int diff = ((cfindex != t->findex) || /* diff font */
(lpmatch != pmatch) || /* diff font */
(Abs(csize - t->size) > 0.1)); /* diff size */
/* if no backing store, can't rasterize */
if (lxi == lxf || !spp)
{
M_err("TextRasterize", "Failed to rasterize");
return;
}
if (!attribute_diff(t) && !diff && !incomplete && rastext)
return;
/* if last is incomplete, need to re-generate the text */
if ((incomplete = (lxi <= 0 || lyi <= 0 || lxf >= win_w || lyf >= win_h)))
{
int mx, my;
WHERE_R2W(mx, my, win_xo, win_yo);
t->xi = mx;
t->yi = my;
sgl_text_move(t);
}
rasw = lxf - lxi + 1;
rash = lyf - lyi + 1;
M_info("RasterizeText", "w=%d h=%d", rasw, rash);
free_mat(rastext);
rastext = get_mat(rash, rasw, imgptr->esize);
PI_rectread(lxi, lyi, lxf, lyf, rastext[0]);
PI_rectwrite(lxi, lyi, lxf, lyf, spp[0]);
/*
* check to make sure that the magic pixel is NOT one of the text color,
* background color or framecolor
*/
while (bad_magic_pix(magicpix))
magicpix++;
set_magic_pix(magicpix);
if (IS_CPACK(imgptr))
{
rgba_t *p, *q, *qs;
/* rasterize */
p = spp[0];
q = rastext[0];
qs = q + rash * rasw;
while (q < qs)
{
*q = (*q == *p) ? magicpix : *q;
q++;
p++;
}
}
else
{
ci_t *p, *q, *qs;
/* rasterize */
p = spp[0];
q = rastext[0];
qs = q + rash * rasw;
while (q < qs)
{
*q = (*q == *p) ? magicpix : *q;
q++;
p++;
}
}
cfindex = t->findex;
csize = t->size;
lpmatch = pmatch;
if (incomplete)
{
text_draw(t);
}
/* update for possible sgl_text_move call */
incomplete = (lxi <= 0 || lyi <= 0 || lxf >= win_w || lyf >= win_h);
}
static void
sim_dbl_text_move(Text_t * t)
{
if (!rastext)
{
text_move(t);
return;
}
get_bounding_box(t);
sim_dbl_swap(imgptr, rasw, rash, rastext,
xi - EXTRA, yi - EXTRA, lxi - EXTRA, lyi - EXTRA, O_MASK);
save_last_position();
}
#endif /* } */
/*********************************************************************
* In addition of saving current text
* NL indicates move the current text "down" 1 line
*********************************************************************/
static void
save_text(int nl)
{
int k = strlen(strbuf);
/* if empty string, do nothing */
if (k == 0)
return;
if (immediate)
{ /* need to render it into raster */
set_current_window(win_id);
if (double_buf)
text_draw(tptr);
fb_to_ras(limg, make_rect(lxi, lyi, lxf - lxi + 1, lyf - lyi - 1));
if (!spp)
spp = get_mat(lyf - lyi + 1, lxf - lxi + 1, limg->esize);
Rectread(lxi, lyi, lxf, lyf, spp[0]);
}
else
{
text_save(); /* save it to structure */
/*
* do it one more time so that next save under will not screw up
* the move
*/
lxi = lxf = -1;
text_draw(tptr);
}
/* requested nextline, figure out where it should be */
if (nl)
{
float dh = 1.02 * tptr->height;
tptr->xi += dh * sin(tptr->rot * PI / 180.0);
tptr->yi -= dh * cos(tptr->rot * PI / 180.0);
lxi = lxf = -1;
text_move(tptr);
}
}
/******************************************************************
* wm_handler is called by repaint to handle unknown repaint
* events from the window manager, e.g., resize, position change etc.
******************************************************************/
static int
text_wm_handler(IPTR im, int wme)
{
static int imxi, imyi;
if (wme > 0)
{
tptr->xi += (im->xi - imxi);
tptr->yi += (im->yi - imyi);
lxi += (im->xi - imxi);
lyi += (im->yi - imyi);
lxf += (im->xi - imxi);
lyf += (im->yi - imyi);
}
imxi = im->xi;
imyi = im->yi;
/*
* display text at the new location will be taken care of by
* display_text, which is called by the dispatcher in do_repaint
*/
return 0;
}
/***********************************************************
* Process keyboard input
***********************************************************/
static int
text_keybd(Text_t * t, int val)
{
int ret = 0;
static int step = 1;
switch (val)
{
case 'h':
case 'H':
t->xi -= step;
break;
case 'j':
case 'J':
t->yi -= step;
break;
case 'k':
case 'K':
t->yi += step;
break;
case 'l':
case 'L':
t->xi += step;
break;
case 27:
ret = -1;
break;
default:
if (val > '0' && val <= '9')
step = val - '0';
ret = 1;
break;
}
if (ret >= 0)
{
text_move(tptr);
ret = 0;
}
return ret;
}
/*******************************************************
* This is the global entry point
********************************************************/
int
do_text(IPTR im)
{
short val;
int done;
if (init_text() <= 0)
return -1;
install_wm_handler(text_wm_handler);
text_wm_handler(im, 0); /* initialize position */
limg = im;
lastwme = 0;
bit_show_form(textform, FL_PLACE_MOUSE, 0, "Text");
active = 1;
/*
* setting lxi < 0 effectively prevents the text rendering routine from
* repaint last postion
*/
lxi = lxf = -1;
tptr->line = &cline;
set_text_default(tptr);
render_text(tptr);
done = 0;
do
{
switch (bit_qread(&val))
{
case LEFTMOUSE:
if (val)
handle_mouse(tptr);
break;
case KEYBD:
done = text_keybd(tptr, val);
break;
case UPARROWKEY:
if (val)
text_keybd(tptr, 'k');
break;
case DOWNARROWKEY:
if (val)
text_keybd(tptr, 'j');
break;
case LEFTARROWKEY:
if (val)
text_keybd(tptr, 'h');
break;
case RIGHTARROWKEY:
if (val)
text_keybd(tptr, 'l');
break;
}
}
while (!done);
/*
* note resetting of active must appear before hide_form since hide_form
* generates an input event(bug?) and by that time line might've been
* freed
*/
hide_getcolor();
remove_wm_handler(text_wm_handler);
active = 0;
#ifndef SGL_BUF
if (double_buf)
{
if (lastwme)
restore_piece(lxi, lyi, lxf, lyf);
swapbuffers();
lastwme = 0;
}
#endif
restore_piece(lxi, lyi, lxf, lyf);
bit_hide_form(textform);
freeline(&cline);
#ifndef NO_NP_DBL
free_mat(rastext);
rastext = 0;
set_magic_pix(0);
#endif
#ifdef READSCR
free_mat(spp);
spp = 0;
#endif
return 0;
}
/************************************************************************
* Call back routine when the state of size button/counter is changed.
* Shadow strength should be a function of of the font size
***********************************************************************/
/* ARGSUSED */
static void
preview_cb(FL_OBJECT * ob, long p)
{
pmatch = fl_get_choice(ob) > 1;
fmprintermatch(pmatch);
render_text(tptr);
}
/* ARGSUSED */
static void
fontsize_cb(FL_OBJECT * p, long q)
{
int i;
if (p == scounter)
{
tptr->size = fl_get_counter_value(p);
for (i = 0; i < sizeof(fsize) / sizeof(float); i++)
{
/*
* if the size matches one of the predefined size, lit up the
* button
*/
fl_set_button(size[i], (fabs(tptr->size - fsize[i]) < 0.05));
}
}
else
{
tptr->size = fsize[q];
fl_set_counter_value(scounter, tptr->size);
}
render_text(tptr);
}
/* ARGSUSED */
static void
justification_cb(FL_OBJECT * p, long q)
{
tptr->place = placement = fl_get_choice(p) - 1;
}
/* ARGSUSED */
static void
select_orientation(FL_OBJECT * p, long q)
{
int i;
static float lastc;
if (p == rcounter)
{
tptr->rot = fl_get_counter_value(p);
if (fabs(tptr->rot - 360.0) < 0.5)
{
tptr->rot = 0;
fl_set_counter_value(p, 0.0);
}
for (i = 0; i < sizeof(rangle) / sizeof(float); i++)
{
/*
* if current angle matches predefined angles, lit up the
* button else turn it off
*/
fl_set_button(ra[i], (fabs(tptr->rot - rangle[i]) < 0.5));
}
}
else
{
tptr->rot = rangle[q];
fl_set_counter_value(rcounter, tptr->rot);
}
/* redraw text only if different from last */
if (fabs(lastc - tptr->rot) > 0.5)
render_text(tptr);
lastc = tptr->rot;
}
/***************************************************************
* New font request
**************************************************************/
/* ARGSUSED */
static void
select_font(FL_OBJECT * p, long q)
{
int f = fl_get_choice(fchoice) - 1;
if (f >= 0)
tptr->findex = f;
render_text(tptr);
}
/********************************************************************
* call back routine when new text is entered
******************************************************************/
/* ARGSUSED */
static void
get_newtext(FL_OBJECT * p, long q)
{
/*
* It would appear that hiding a form generates an input event and this
* routine will be called. Must turn active off before hiding form
*/
if (!active)
return;
Strncpy(strbuf, fl_get_input(input), MAXSTR);
tokenize(strbuf, tptr->line, tptr->size);
text_move(tptr);
}
/****************************************************************
* Color call back routine. If the image is colormap, counted on
* get_color to do the right thing with the colormap index
***************************************************************/
static int currentq; /* color current working on */
static void
handle_color_change(int cc[])
{
int q = currentq;
static int lastq;
tptr->col[q][0] = cc[0];
tptr->col[q][1] = cc[1];
tptr->col[q][2] = cc[2];
tptr->col[q][3] = cc[3];
if (lastq != q)
get_bounding_box(tptr);
/* we have to always keep the backbuffer clean */
#if 1
render_text(tptr);
#else
(double_buf ? text_move : text_draw) (tptr);
#endif
lastq = q;
diffcolor = 1;
}
/*****************************************************************
* call back routine for which color currently we are working on
****************************************************************/
/* ARGSUSED */
static void
select_color_cb(FL_OBJECT * p, long q)
{
currentq = q;
set_getcolor_cb(handle_color_change);
get_color(imgptr, lcol[q], 0);
}
/**************************************************************
* misc. changes
*************************************************************/
/* ARGSUSED */
static void
se_call_back(FL_OBJECT * p, long q)
{
tptr->se = fl_get_choice(effects) - 1;
render_text(tptr);
}
/* ARGSUSED */
static void
frame_bk_cb(FL_OBJECT * p, long q)
{
static int lframe, lbk, leffects;
tptr->frame = fl_get_button(frame);
tptr->bk = fl_get_button(bk);
tptr->se = fl_get_choice(effects) - 1;
if (!tptr->bk)
{
fl_set_object_lcol(col[2], FL_INACTIVE);
fl_deactivate_object(col[2]);
}
else
{
fl_set_object_lcol(col[2], FL_BLACK);
fl_activate_object(col[2]);
}
if (!tptr->frame)
{
fl_set_object_lcol(col[1], FL_INACTIVE);
fl_deactivate_object(col[1]);
}
else
{
fl_set_object_lcol(col[1], FL_BLACK);
fl_activate_object(col[1]);
}
if (lframe - tptr->frame || lbk - tptr->bk || leffects - tptr->se)
{
render_text(tptr);
lframe = tptr->frame;
lbk = tptr->bk;
leffects = tptr->se;
}
}
/*****************************************************************
* finish up
*****************************************************************/
/* ARGSUSED */
static void
text_finish(FL_OBJECT * obj, long q)
{
fl_qenter(KEYBD, 27);
/* left do_text do the cleanup */
}
/*****************************************************************
* Delete all text. Real work is done by del_text. This is just
* to get the prototype right
*******************************************************************/
/* ARGSUSED */
static void
del_dummy(FL_OBJECT * q, long p)
{
del_text(); /* this routine sets totaltext to zero */
imgptr->io->display(imgptr, 0, 1);
render_text(tptr);
}
/*********************************************************
* Request a saving: if q == 1, newline
*********************************************************/
/* ARGSUSED */
static void
save_cb(FL_OBJECT * obj, long q)
{
save_text(q);
}
/*******************************************************************
* Main form
******************************************************************/
static void
create_form_text(void)
{
FL_OBJECT *obj;
const char *sep = "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=";
static int ok;
float x, y, dx, dy;
int i;
if (ok)
return;
textform = fl_bgn_form(FL_NO_BOX, 295.0, 310.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 295.0, 310.0, "");
fl_set_object_color(obj, 9, 47);
obj = fl_add_button(FL_HIDDEN_BUTTON, 0.0, 0.0, 295.0, 310.0, "");
fl_set_call_back(obj, help_cb, HELP_TEXT);
/* font */
fchoice = obj = fl_add_choice(FL_NCH, 60.0, 270.0, 210.0, 25.0, "Font");
fl_set_object_boxtype(obj, FL_RSHADOW_BOX);
fl_set_call_back(obj, select_font, 0);
fl_set_choice_fontsize(obj, 11.0);
/* input */
input = obj = fl_add_input(FL_NORMAL_INPUT, 10.0, 40.0, 275.0, 20.0, "");
fl_set_object_boxtype(obj, FL_BORDER_BOX);
fl_set_object_color(obj, 13, 50);
fl_set_object_lsize(obj, 8.0);
fl_set_call_back(obj, get_newtext, 0);
obj = fl_add_text(FL_NT, 5.0, 145.0, 280.0, 10.0, sep);
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
/* size group */
fl_bgn_group();
dx = 30.0;
dy = 30.0;
for (x = 15, y = 190, i = 0; i < 6; i += 2, y -= 20)
{
size[i] = obj = fl_add_roundbutton(FL_RB, x, y, dx, dy, "");
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, fontsize_cb, i);
size[i + 1] = obj = fl_add_roundbutton(FL_RB, x + 65, y, dx, dy, "");
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, fontsize_cb, i + 1);
}
fl_end_group();
scounter = obj = fl_add_counter(FL_NC, 15.0, 220.0, 115.0, 25.0, "Size");
fl_set_object_color(obj, 12, 4);
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_align(obj, FL_ALIGN_TOP);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, fontsize_cb, 0);
/* direction group */
x = 160.0;
y = 190.0;
dy = 30;
fl_bgn_group();
for (i = 0; i < 4; i += 2, y -= dy)
{
ra[i] = obj = fl_add_roundbutton(FL_RB, x, y, 30.0, dy, "");
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, select_orientation, i);
ra[i + 1] = obj = fl_add_roundbutton(FL_RB, 225.0, y, 30.0, dy, "");
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, select_orientation, i + 1);
}
rcounter = obj = fl_add_counter(FL_NC, 155, 220, 120, 25, "Rotation");
fl_set_object_color(obj, 12, 4);
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_align(obj, FL_ALIGN_TOP);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_call_back(obj, select_orientation, 0);
fl_end_group();
/* misc group */
fl_bgn_group();
col[0] = obj = fl_add_roundbutton(FL_NB, 15, 90, 30, 30, "TextColor");
fl_set_object_color(obj, 7, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, select_color_cb, TC);
col[1] = obj = fl_add_roundbutton(FL_NB, 100.0, 90.0, 30, 30, "FrameCol");
fl_set_object_color(obj, 7, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_object_lcol(obj, FL_INACTIVE);
fl_deactivate_object(obj);
fl_set_call_back(obj, select_color_cb, FC);
col[2] = obj = fl_add_roundbutton(FL_NB, 190, 90, 30, 30, "BackgrdCol");
fl_set_object_color(obj, 7, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, select_color_cb, BC);
fl_set_object_lcol(obj, FL_INACTIVE);
fl_deactivate_object(obj);
frame = obj = fl_add_roundbutton(FL_PB, 100, 115, 30, 30.0, "Frame");
fl_set_object_color(obj, 7, 1);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, frame_bk_cb, 0);
bk = obj = fl_add_roundbutton(FL_PB, 190.0, 115.0, 35, 30, "Background");
fl_set_object_color(obj, 7, 1);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, frame_bk_cb, 0);
/* Special effects */
effects = obj = fl_add_choice(FL_NCH, 20, 120.0, 80, 25, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_choice_fontsize(obj, 10.0);
i = 0;
while (seffect_name[i])
{
fl_addto_choice(obj, seffect_name[i]);
i++;
}
fl_set_choice(obj, 1);
fl_set_call_back(obj, se_call_back, 0);
x = 20.0;
y = 65.0;
dx = 80;
dy = 25;
obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_choice_fontsize(obj, 10.0);
fl_addto_choice(obj, "Left");
fl_addto_choice(obj, "Center");
fl_addto_choice(obj, "Right");
fl_set_choice(obj, placement + 1);
fl_set_call_back(obj, justification_cb, 0);
x += dx + 5;
obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_choice_fontsize(obj, 10.0);
fl_addto_choice(obj, "ScreenFont");
fl_addto_choice(obj, "PrinterFont");
fl_set_call_back(obj, preview_cb, 0);
x += dx + 5;
obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
fl_set_choice_fontsize(obj, 10.0);
fl_addto_choice(obj, "Deferred");
fl_addto_choice(obj, "Immediate");
fl_set_choice(obj, immediate + 1);
fl_set_call_back(obj, immediate_cb, 0);
fl_end_group();
dx = 65.0;
dy = 25.0;
x = 20;
fl_bgn_group();
obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "DelAll");
fl_set_call_back(obj, del_dummy, 0);
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, FL_RED);
obj = fl_add_button(FL_NB, x + dx, 10.0, dx, dy, "Done");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
fl_set_call_back(obj, text_finish, 0);
obj = fl_add_button(FL_NB, x + 2.0 * dx, 10.0, dx, dy, "NewLine");
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, save_cb, 1);
obj = fl_add_button(FL_NB, x + 3.0 * dx, 10.0, dx, dy, "OK");
fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, save_cb, 0);
fl_end_group();
fl_end_form();
ok = 1;
}